/**
  ******************************************************************************
  * @file    adc.c
  * @author  hyseim software Team
  * @date    05-Sep-2023
  * @brief   This file provides all the adc functions.
  ******************************************************************************
  * @attention
  *
  * Copyright (c) 2020 Hyseim. Co., Ltd.
  * All rights reserved.
  *
  * This software is licensed under terms that can be found in the LICENSE file
  * in the root directory of this software component.
  * If no LICENSE file comes with this software, it is provided AS-IS.
  *
  ******************************************************************************
  */

/* Includes ------------------------------------------------------------------*/
#include "common.h"
#include "adc.h"

/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
/* Private functions ---------------------------------------------------------*/

/**
 * @brief  Initializes the ADCx peripheral according to the specified 
 *         parameters in the ADC_InitStruct.
 * @param  ADCx: Pointer to selected ADC peripheral.
 *         This parameter can be one of the following values:
 *         ADC0, ADC1.
 * @param  ADC_InitStruct: pointer to a ADC_InitStruct_t structure
 *         that contains the configuration information for the specified 
 *         ADC peripheral.
 * @return None
 */
void ADC_Init(ADC_t* ADCx, ADC_InitStruct_t* ADC_InitStruct)
{
    ADCx->ADDR_AD_PD = 0x3;

    if(ADC_InitStruct->sampgMode != NCH_MODE)
    {
        ADCx->ADDR_AD_GROUP_SET_CIF1 = (ADC_InitStruct->group1Trigger|
                                        ADC_InitStruct->group2Trigger|
                                        ADC_InitStruct->group3Trigger|
                                        ADC_InitStruct->group4Trigger|
                                        ADC_InitStruct->group5Trigger);
    }
    else
    {
        ADCx->ADDR_AD_GROUP_SET_CIF1 = (ADC_InitStruct->group1Trigger|
                                       (ADC_InitStruct->group2Trigger << 8)|
                                       (ADC_InitStruct->group3Trigger << 16)|
                                       (ADC_InitStruct->group4Trigger << 24));
        ADCx->ADDR_AD_GROUP_SET_CIF2 = ADC_InitStruct->group5Trigger;
    }

    ADCx->ADDR_AD_CER = (ADC_InitStruct->dataPrecision|
                        ADC_InitStruct->readClear|
                        ADC_InitStruct->anyChannelInterruptEn|
                        ADC_InitStruct->dataFormat);

    ADCx->ADDR_AD_CSR |= (ADC_InitStruct->externTriggerMode|
                         ADC_InitStruct->atuTriggerMode|
                         ADC_InitStruct->sampgMode|
                         ADC_InitStruct->pdbEn|
                         ADC_InitStruct->pdbSoftEn|
                         ADC_InitStruct->nchSeqSample|
                         ADC_InitStruct->setPendingCh|
                         ADC_InitStruct->pendingTrigger|
                         ADC_InitStruct->interruptEn|
                         0 << 2);
}

/**
 * @brief  Nch mode channel configuration.
 * @param  ADCx: Pointer to selected ADC peripheral.
 *         This parameter can be one of the following values:
 *         ADC0, ADC1.
 * @param  ADC_NchConfigStruct:Pointer to the ADC Nch mode channel configuration 
 *         information in the ADC Nch ConfigStruct_t structure, which contains 
 *         the specified ADC Nch mode channel configuration information
 * @return None
 */
void ADC_NchCofig(ADC_t* ADCx, ADC_NchConfigStruct_t* ADC_NchConfigStruct)
{
    ADCx->ADDR_AD_TRIGGER1_CIF = (ADC_NchConfigStruct->group1Ch0 << 0|
                                  ADC_NchConfigStruct->group1Ch0En << 5|
                                  ADC_NchConfigStruct->group1Ch1 << 8|
                                  ADC_NchConfigStruct->group1Ch1En << 13|
                                  ADC_NchConfigStruct->group1Ch2 << 16|
                                  ADC_NchConfigStruct->group1Ch2En << 21|
                                  ADC_NchConfigStruct->group1Ch3 << 24|
                                  ADC_NchConfigStruct->group1Ch3En << 29);

    ADCx->ADDR_AD_TRIGGER1_CIF_EXPAND = (ADC_NchConfigStruct->group1Ch4 << 0|
                                         ADC_NchConfigStruct->group1Ch4En << 5|
                                         ADC_NchConfigStruct->group1Ch5 << 8|
                                         ADC_NchConfigStruct->group1Ch5En << 13);
                                         
    ADCx->ADDR_AD_TRIGGER2_CIF = (ADC_NchConfigStruct->group2Ch0 << 0|
                                  ADC_NchConfigStruct->group2Ch0En << 5|
                                  ADC_NchConfigStruct->group2Ch1 << 8|
                                  ADC_NchConfigStruct->group2Ch1En << 13|
                                  ADC_NchConfigStruct->group2Ch2 << 16|
                                  ADC_NchConfigStruct->group2Ch2En << 21|
                                  ADC_NchConfigStruct->group2Ch3 << 24|
                                  ADC_NchConfigStruct->group2Ch3En << 29);

    ADCx->ADDR_AD_TRIGGER2_CIF_EXPAND = (ADC_NchConfigStruct->group2Ch4 << 0|
                                         ADC_NchConfigStruct->group2Ch4En << 5|
                                         ADC_NchConfigStruct->group2Ch5 << 8|
                                         ADC_NchConfigStruct->group2Ch5En << 13);

    ADCx->ADDR_AD_TRIGGER3_CIF = (ADC_NchConfigStruct->group3Ch0 << 0|
                                  ADC_NchConfigStruct->group3Ch0En << 5|
                                  ADC_NchConfigStruct->group3Ch1 << 8|
                                  ADC_NchConfigStruct->group3Ch1En << 13|
                                  ADC_NchConfigStruct->group3Ch2 << 16|
                                  ADC_NchConfigStruct->group3Ch2En << 21|
                                  ADC_NchConfigStruct->group3Ch3 << 24|
                                  ADC_NchConfigStruct->group3Ch3En << 29);
                            
    ADCx->ADDR_AD_TRIGGER4_CIF = (ADC_NchConfigStruct->group4Ch0 << 0|
                                  ADC_NchConfigStruct->group4Ch0En << 5|
                                  ADC_NchConfigStruct->group4Ch1 << 8|
                                  ADC_NchConfigStruct->group4Ch1En << 13|
                                  ADC_NchConfigStruct->group4Ch2 << 16|
                                  ADC_NchConfigStruct->group4Ch2En << 21|
                                  ADC_NchConfigStruct->group4Ch3 << 24|
                                  ADC_NchConfigStruct->group4Ch3En << 29);

    ADCx->ADDR_AD_TRIGGER5_CIF = (ADC_NchConfigStruct->group5Ch0 << 0|
                                  ADC_NchConfigStruct->group5Ch0En << 5|
                                  ADC_NchConfigStruct->group5Ch1 << 8|
                                  ADC_NchConfigStruct->group5Ch1En << 13|
                                  ADC_NchConfigStruct->group5Ch2 << 16|
                                  ADC_NchConfigStruct->group5Ch2En << 21|
                                  ADC_NchConfigStruct->group5Ch3 << 24|
                                  ADC_NchConfigStruct->group5Ch3En << 29);
}

/**
 * @brief  single隆垄onecycle隆垄continue mode channel configuration.
 * @param  ADCx: Pointer to selected ADC peripheral.
 *         This parameter can be one of the following values:
 *         ADC0, ADC1.
 * @param  startCh:Sampling start channel 
 * @param  stopCh:Sampling end channel 
 * @return None
 */
void ADC_SetCh(ADC_t* ADCx, uint32_t startCh, uint32_t stopCh)
{
    ADCx->ADDR_AD_ADANS = (startCh | stopCh << 7);
}

/**
 * @brief  Enables or disables the specified ADC peripheral.
 * @param  ADCx: Pointer to selected ADC peripheral.
 *         This parameter can be one of the following values:
 *         ADC0, ADC1.
 * @param  NewState: new state of the ADCx peripheral.
 *         This parameter can be: ENABLE or DISABLE.
 * @return None
 */
void ADC_Cmd(ADC_t* ADCx, FunctionalState_t NewState)
{
    if (NewState != DISABLE) {
        ADCx->ADDR_AD_CSR |= BIT(7);
    }
    else {
        ADCx->ADDR_AD_CSR = (ADCx->ADDR_AD_CSR & (~BIT(7)));
    }
}

/**
 * @brief  TS interrupt enable or disable.
 * @param  ADCx: Pointer to selected ADC peripheral.
 *         This parameter can be one of the following values:
 *         ADC0, ADC1.
 * @param  ADC_TsConfigStruct:Pointer to the ADC ts mode channel configuration 
 *         information in the ADC ADC_TsConfigStruct_t structure, which contains 
 *         the specified ADC ts interrupt enable situation
 * @return None
 */
void ADC_TsIrqEn(ADC_t* ADCx, ADC_TsConfigStruct_t* ADC_TsConfigStruct)
{
    ADCx->ADDR_TS_CONF0 = (ADC_TsConfigStruct->tsOverflowIrq|
                           ADC_TsConfigStruct->tsUnderflowIrq|
                           ADC_TsConfigStruct->tsIrq);
}

/**
 * @brief  Set temperature overflow value.
 * @param  ADCx: Pointer to selected ADC peripheral.
 *         This parameter can be one of the following values:
 *         ADC0, ADC1.
 * @param  overflowValue:Temperature Overflow. 
 * @return None
 */
void ADC_TsOverflowValue(ADC_t* ADCx, uint16_t overflowValue)
{
    ADCx->ADDR_TS_CONF1 |= overflowValue << 16;
}

/**
 * @brief  Set temperature underflow value.
 * @param  ADCx: Pointer to selected ADC peripheral.
 *         This parameter can be one of the following values:
 *         ADC0, ADC1.
 * @param  overflowValue:Temperature Underflow. 
 * @return None
 */
void ADC_TsUnderflowValue(ADC_t* ADCx, uint16_t underflowValue)
{
    ADCx->ADDR_TS_CONF1 |= underflowValue;
}

/**
 * @brief  Shadow0 mode configuration.
 * @param  ADCx: Pointer to selected ADC peripheral.
 *         This parameter can be one of the following values:
 *         ADC0, ADC1.
 * @param  setCh:Channel Configuration. 
 * @return None
 */
void ADC_Shadow0Config(ADC_t* ADCx, FunctionalState_t NewState, uint32_t setCh)
{
    if (NewState != DISABLE) {
        ADCx->ADDR_AD_RABSET_CIF |= (setCh | 1<< 5);
    }
    else {
        ADCx->ADDR_AD_RABSET_CIF |= (0 << 5);
    } 
}

/**
 * @brief  Shadow1 mode configuration.
 * @param  ADCx: Pointer to selected ADC peripheral.
 *         This parameter can be one of the following values:
 *         ADC0, ADC1.
 * @param  setCh:Channel Configuration. 
 * @return None
 */
void ADC_Shadow1Config(ADC_t* ADCx, FunctionalState_t NewState, uint32_t setCh)
{
    if (NewState != DISABLE) {
        ADCx->ADDR_AD_RABSET_CIF |= (setCh << 8 | 1<< 13);
    }
    else {
        ADCx->ADDR_AD_RABSET_CIF |= (0 << 13);
    }
}

/**
 * @brief  ADC clock division setting.
 * @param  ADCx: Pointer to selected ADC peripheral.
 *         This parameter can be one of the following values:
 *         ADC0, ADC1.
 * @param  divFactor:Clock divide factor. 
 * @return None
 */
void ADC_ClkDiv(ADC_t* ADCx, uint32_t divFactor)
{
    ADCx->ADDR_AD_CLK_DIV = (divFactor | 1 << 8);
}

/**
 * @brief  ADC interrupt configuration.
 * @param  ADCx: Pointer to selected ADC peripheral.
 *         This parameter can be one of the following values:
 *         ADC0, ADC1.
 * @param  ADC_InterruptConfig:Pointer to the ADC interrupt configuration 
 *         information in the ADC ADC_InterruptConfig_t structure, which contains 
 *         the specified ADC interrupt mode channel configuration information
 * @return None
 */
void ADC_InterruptConfig(ADC_t* ADCx, ADC_InterruptConfig_t* ADC_InterruptConfig)
{
    ADCx->ADDR_AD_INTC = (ADC_InterruptConfig->dmaReq|
                          ADC_InterruptConfig->interruptReq|
                          ADC_InterruptConfig->errorInterruptReq|
                          ADC_InterruptConfig->chFinsh);
}

/**
 * @brief  ADC soft start cmd.
 * @param  ADCx: Pointer to selected ADC peripheral.
 *         This parameter can be one of the following values:
 *         ADC0, ADC1.
 * @return None
 */
void ADC_SoftStartSample(ADC_t* ADCx, FunctionalState_t NewState)
{
    if (NewState != DISABLE) {
        ADCx->ADDR_AD_CSR |= (1 << 23);
    }
    else {
        ADCx->ADDR_AD_CSR |= (0 << 23);
    }
}

/**
 * @brief  ADC clear interrupt cmd.
 * @param  ADCx: Pointer to selected ADC peripheral.
 *         This parameter can be one of the following values:
 *         ADC0, ADC1.
 * @return None
 */
void ADC_InterruptClear(ADC_t* ADCx)
{
    ADCx->ADDR_AD_INTC |= (1 << 8);
}

/**
 * @brief  ADC analog sampling time configuration.
 * @param  ADCx: Pointer to selected ADC peripheral.
 *         This parameter can be one of the following values:
 *         ADC0, ADC1.
 * @param  SampleTime:Pointer to the ADC sample time configuration  
 *         information in the  ADC_SampleTime_t structure, which 
 *         contains the specified analog sample time configuration information
 * @return None
 */
void ADC_SampleTimeSet(ADC_t* ADCx, ADC_SampleTime_t* SampleTime)
{
    ADCx->ADDR_AD_SSTR = (SampleTime->tmux << 28|
                          SampleTime->thold << 24|
                          SampleTime->tgap << 8|
                          SampleTime->tde);
}